/*
 * File: ControlService.java
 * 
 * Change Log
 * Author				DTG				Description of Change
 * ---------------------------------------------------------------------------
 * Timothy M. Lemm		18OCT11 0729	Initial Service Structure
 * 										Added binding to Core Service
 * 										Accepting Binds Support added 	
 * 
 * Timothy M. Lemm		19OCT11 1731	initial public methods added	
 * 
 * Timothy M. Lemm		19OCT11 2016	Compass and Gyro routines added
 */

package com.erau.droidsatframework.control;

import com.erau.droidsatframework.core.CoreService;
import com.erau.droidsatframework.core.CoreService.CoreBinder;

import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Binder;
import android.os.IBinder;
import android.widget.Toast;

public class ControlService extends Service {

	private SensorManager adcSensorManagement;
	private Sensor adcGyroSensor;
	private Sensor adcCompassSensor;
	
	private final IBinder localBinder = new ControlBinder(); //For dealing with incoming bind from control algo
	CoreService core;					//Local handle of the CoreService Instance for binding
	
	private boolean isBound = false;	//Status indicator of being bound or not to the core
	
	private float[] gyroRates = new float[3];
	private float[] gyroAngles = new float[3];
	private float[] compassPositions = new float[3];
	private float lastTimestamp = 0;
	private float compassReference;

	
	@Override
	public IBinder onBind(Intent intent) {
		return localBinder;
	}
	
	//CLASS: ControlBinder
	//Class that contains the information for the CoreService... 
	//We have a method so that multiple things can bind into us...
	public class ControlBinder extends Binder {
		public ControlService getService() {
			return ControlService.this;
		}//End getService
	}//End ControlBincer
	
	@Override
	public void onCreate() {
		
		//Bind back to core
		Intent control2CoreIntent = new Intent(this, CoreService.class);  //Intent to bind to core
		bindService(control2CoreIntent, bindConnection, Context.BIND_AUTO_CREATE ); //Bind
		
		//Setup the sensors
		adcSensorManagement = (SensorManager) getSystemService(SENSOR_SERVICE);
		adcGyroSensor = adcSensorManagement.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
		adcCompassSensor = adcSensorManagement.getDefaultSensor(Sensor.TYPE_ORIENTATION);
		adcSensorManagement.registerListener(adcSensorListener, adcGyroSensor, SensorManager.SENSOR_DELAY_GAME);
		adcSensorManagement.registerListener(adcSensorListener, adcCompassSensor, SensorManager.SENSOR_DELAY_GAME);
	}
	
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		return START_NOT_STICKY; //We can die
	}//End onStartCommand
	
	//CLASS EXTENSION: bindConnection
	//Required class extension of Service Connection to provide a call 
	//back for the system to pass the bound interface back
	private ServiceConnection bindConnection = new ServiceConnection() {

		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			CoreBinder coreBinder = (CoreBinder) service; //cast the call back service into the core binder
			core = coreBinder.getService();	//bring in the active instance of the core service
			isBound = true;		//update status flag			
			
		}

		@Override
		public void onServiceDisconnected(ComponentName name) {
			isBound = false; //update status flag	
		}
	};
	SensorEventListener adcSensorListener = new SensorEventListener() {
		
		@Override
		public void onSensorChanged(SensorEvent event) {
			
				Sensor eventSensor = event.sensor;
			
				if(eventSensor.equals(adcGyroSensor)){
					if (lastTimestamp != 0) {
			              final float deltaTime = (event.timestamp - lastTimestamp) * CONTROL_CONSTANTS.NANO_SEC_TO_SEC;
			              
			              //Hand off the anglular rates
			              gyroRates = event.values;
			              
			              //Convert and hand off angular position
			              gyroAngles[0] = event.values[0]*deltaTime;
			              gyroAngles[1] = event.values[1]*deltaTime;
			              gyroAngles[2] = event.values[2]*deltaTime;
			              
			          }
			          lastTimestamp = event.timestamp; //Update for deltaTime
			       }//End if gyro
				
				if(eventSensor.equals(adcCompassSensor)){
					compassPositions = event.values;
				}//End if orientation
		}//sensor change
		
		@Override
		public void onAccuracyChanged(Sensor sensor, int accuracy) {
			//lol we dont care...
		}			
		
	};
	
	public float getGyroAngleX(){
		return gyroAngles[0];
	}//End getGryroX
	
	public float getGyroAngleY(){
		return gyroAngles[1];
	}//End getGyroY
	
	public float getGyroAngleZ(){
		return gyroAngles[2];
	}//End getGyroZ
	
	public float[] getGyroAngles(){
		return gyroAngles;
	}//End getGyroAngles
	
	public float getGyroRateX(){
		return gyroRates[0];
	}//End getGryroX
	
	public float getGyroRateY(){
		return gyroRates[1];
	}//End getGyroY
	
	public float getGyroRateZ(){
		return gyroRates[2];
	}//End getGyroZ
	
	public float[] getGyroRates(){
		return gyroRates;
	}//End getGyroRates
	
	public float getCompassPositionX(){
		return compassPositions[0];
	}//End getCompassPosX
	
	public float getCompassPositionY(){
		return compassPositions[1];	
	}//End getCompassPosY

	public float getCompassPositionZ(){
		return compassPositions[2];
	}//End getCompassPosZ
	
	public float[] getCompassPositions(){
		return compassPositions;
	}//End getCompassPositions
	
	public float getCompassReference(){
		return compassReference;
	}//End getCompassReference
	
	//METHOD: commandRequest
	//Velocity has an acceptable range from -1000 to 1000
	//Acceleration has an accepable range from 0-1000
	//Axis use the values in CONTROL_CONSTANTS.java
	public void commandRequest(int velocity, int acceleration, int axis){
		
	}//End Command Request

}
